 /******************************************************************************

 Copyright (c) 2012-2016, Texas Instruments Incorporated
 All rights reserved.

 Redistribution and use in source and binary forms, with or without
 modification, are permitted provided that the following conditions
 are met:

 *  Redistributions of source code must retain the above copyright
    notice, this list of conditions and the following disclaimer.

 *  Redistributions in binary form must reproduce the above copyright
    notice, this list of conditions and the following disclaimer in the
    documentation and/or other materials provided with the distribution.

 *  Neither the name of Texas Instruments Incorporated nor the names of
    its contributors may be used to endorse or promote products derived
    from this software without specific prior written permission.

 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
 AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
 THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
 PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
 CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
 EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
 PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
 OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
 WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
 OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
 EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

 ******************************************************************************
 Release Name: ble_sdk_2_02_00_31
 Release Date: 2016-06-16 18:57:29
 *****************************************************************************/

/*********************************************************************
 * INCLUDES
 */

#include <ti/sysbios/BIOS.h>
#include <ti/sysbios/knl/Event.h>
#include <ti/drivers/UART.h>

/* Example/Board Header files */
#include "Board.h"

#include <string.h>

#include "oad/uart_serial_download.h"
#include "oad/oad.h"


/*********************************************************************
 * CONSTANTS
 */

/*********************************************************************
 * MACROS
 */

/*********************************************************************
 * GLOBAL VARIABLES
 */

/*********************************************************************
 * LOCAL VARIABLES
 */
static Event_Handle eventHandle;

static UART_Handle uartHandle;

 uint16_t nextOadBlockNum = 0;
static uint16_t oadBlockWriteStatus = 0;

bool dbgFlagBlockEvent = 0;
bool dbgFlagPendingEvent = 0;
bool dbgFlagStatusPostEvent = 0;
bool dbgFlagRejectPostEvent = 0;
bool dbgFlagNextPostEvent = 0;

/*********************************************************************
 * LOCAL FUNCTIONS
 */
static void USD_getNextBlockReqCb(uint16_t blkNum);
static void USD_rejectImageCb(img_hdr_t *pImgHdr);
static void USD_sendStatusCb(uint8_t status);

static void getNextBlock(uint16_t blkNum, uint8_t* oadBlockBuff);
static void getImgHdr(uint8_t* imgHdrBuff);

void USD_open(Event_Handle eHandle)
{
  oadCBs_t fnOadCBs;
  UART_Params uartParams;

  /* Create a UART with data processing off. */
  UART_Params_init(&uartParams);
  uartParams.writeDataMode = UART_DATA_BINARY;
  uartParams.readDataMode = UART_DATA_BINARY;
  uartParams.readReturnMode = UART_RETURN_FULL;
  uartParams.readEcho = UART_ECHO_OFF;
  uartParams.baudRate = 115200;
  uartHandle = UART_open(Board_UART0, &uartParams);

  eventHandle = eHandle;

  fnOadCBs.pfnOadGetNextBlockReqCb = USD_getNextBlockReqCb;
  fnOadCBs.pfnOadRejectImageCb = USD_rejectImageCb;
  fnOadCBs.pfnOadSendStatusCb = USD_sendStatusCb;

  OAD_init(&fnOadCBs);
}

void USD_close(void)
{
    UART_close(uartHandle);
}

int32_t USD_startFwUpdate(void)
{
    uint8_t imgHdr[16];

    nextOadBlockNum = 0;

    getImgHdr(imgHdr);

    OAD_imgIdentifyWrite(imgHdr);

    return 0;
}

int32_t USD_processFwUpdate(uint32_t events)
{
    int32_t status;

    if (events & USD_EVENT_NEXT_BLOCK) {
        dbgFlagNextPostEvent = 0;
        dbgFlagBlockEvent = 1;
        //allocate buffer for block + block number
        uint8_t blockBuff[OAD_BLOCK_SIZE + 2] = {0};
        getNextBlock(nextOadBlockNum, blockBuff);

        OAD_imgBlockWrite(blockBuff);
        dbgFlagBlockEvent = 0;

        status = 0;
    }
    else if (events & USD_EVENT_REJECTED_IMG) {
        dbgFlagRejectPostEvent = 0;
        nextOadBlockNum = 0;

        status = -1;
    }
    else if (events & USD_EVENT_STATUS) {
        dbgFlagStatusPostEvent = 0;
        // Close the OAD target if it is open
        OADTarget_close();

        if(oadBlockWriteStatus == OAD_SUCCESS)
        {
            status = 1;
        }
        else
        {
            nextOadBlockNum = 0;

            status = -1;
        }
    }
    else
    {
        //what went wrong
        while(1);
    }

    return status;
}

/*********************************************************************
 * @fn      USD_sendStatus
 *
 * @brief   Send status to the OAD Manager if an error occurs
 *
 * @param   connHandle - connection message was received on
 * @param   status - status to OAD Manager.
 *
 * @return  None
 */
static void USD_sendStatusCb(uint8_t status)
{
    dbgFlagStatusPostEvent = 1;
    oadBlockWriteStatus = status;
    Event_post(eventHandle, USD_EVENT_STATUS);
}

/*********************************************************************
 * @fn      OAD_rejectImage
 *
 * @brief   Reject the Image identified by the OAD manager, send back
 *          active image version, length and UID to manager.
 *
 * @param   connHandle - connection message was received on.
 * @param   pImgHdr    - pointer to the img_hdr_t data to send.
 *
 * @return  None.
 */
static void USD_rejectImageCb(img_hdr_t *pImgHdr)
{
  dbgFlagRejectPostEvent = 1;
  Event_post(eventHandle, USD_EVENT_REJECTED_IMG);
}

/*********************************************************************
 * @fn      OAD_getNextBlockReq
 *
 * @brief   Process the Request for next image block.
 *
 * @param   connHandle - connection message was received on
 * @param   blkNum - block number to request from OAD Manager.
 *
 * @return  None
 */
static void USD_getNextBlockReqCb(uint16_t blkNum)
{
    dbgFlagNextPostEvent = 1;
    nextOadBlockNum = blkNum;
    Event_post(eventHandle, USD_EVENT_NEXT_BLOCK);
}

static void getImgHdr(uint8_t* imgHdrBuff)
{
    UART_read(uartHandle, imgHdrBuff, 16);
}

static void getNextBlock(uint16_t blkNum, uint8_t* oadBlockBuff)
{
    uint8_t blkNumLower = blkNum & 0xFF;
    uint8_t blkNumUpper = (blkNum & 0xFF00) >> 8;

    UART_write(uartHandle, &blkNumUpper, 1);
    UART_write(uartHandle, &blkNumLower, 1);

    UART_read(uartHandle, oadBlockBuff, (OAD_BLOCK_SIZE + 2));
}

/*********************************************************************
*********************************************************************/
